<script setup lang="ts">
import type { Directive } from 'vue'

defineOptions({ name: 'RealNumberInput' })

const props = defineProps<{
  initialValue: string | number | null | undefined
  min?: number
  max?: number
  decimalPlaces?: number
  maxlength?: number
}>()
const emit = defineEmits<{
  (e: 'blur', value: number | null): void
  (e: 'input', ...args: any): void
}>()
const internalValue = ref(simpleConvert(props.initialValue))

const vLimit: Directive = {
  mounted(el, binding) {
    const { min, max, decimalPlaces, callback } = binding.value // 获取参数
    const inputElement = el.querySelector('input')

    // 定义一个函数，用于校验和修正输入值
    const validateInput = inputElement._validateInput = () => {
      let value = inputElement.value
      let numericValue = Number.parseFloat(value)
      const decimalRegex = new RegExp(`^\\d+(\\.\\d{0,${decimalPlaces}})?$`)

      // 如果为空，直接返回（允许清空输入框）
      if (value === '' || value === null || value === undefined) {
        value = ''
      }

      // 移除前导零（除非它是 "0" 或 "0.xxx" 的形式）
      if (/^0\d/.test(value) && !/^0(\.\d+)?$/.test(value)) {
        value = value.replace(/^0+/, '') // 移除所有前导零，除非它是单个零或小数
        if (value === '')
          value = '0' // 如果移除后为空，则设为 '0'
      }

      // 尝试将输入值转换为数字（处理可能的非法输入）
      if (Number.isNaN(numericValue) || /[^0-9.]/.test(value)) {
        value = value.replace(/[^0-9.]/g, '')
      }

      if (!decimalRegex.test(value)) { // 限制小数位数
        // 如果小数位数超过限制，修正输入值
        const [integerPart, decimalPart] = value.split('.')
        if (decimalPart) {
          value = `${integerPart}.${decimalPart.slice(0, decimalPlaces)}`
        }
        else {
          value = integerPart
        }
      }

      numericValue = Number.parseFloat(value) // 更新解析后的数值

      // 限制范围
      if (numericValue < min) {
        numericValue = min
        value = min.toString()
      }
      else if (numericValue > max) {
        numericValue = max
        value = max.toString()
      }

      // console.log('input: ', inputElement.value, value)

      internalValue.value = inputElement.value = value

      if (callback) {
        callback(value, numericValue)
      }
    }

    // 监听输入事件
    inputElement.addEventListener('input', validateInput)
  },
  unmounted(el) {
    const inputElement = el.querySelector('input')
    inputElement.removeEventListener('input', inputElement._validateInput, false)
    delete inputElement._validateInput
  },
}

function onBlur() {
  emit('blur', simpleConvert(internalValue.value))
}

function simpleConvert(value: string | number | null | undefined): number | null {
  if (value === null || value === undefined) {
    return null
  }
  const v = Number.parseFloat(value.toString())
  return Number.isNaN(v) ? null : v
}

watch(() => props.initialValue, (value) => {
  internalValue.value = simpleConvert(value)
})
</script>

<template>
  <ElInput
    v-model="internalValue"
    v-limit="{ min: min || 0, max: max || 99999999999, decimalPlaces: decimalPlaces || 6 }"
    placeholder="请输入数值" class="free"
    clearable
    :maxlength="maxlength || 16"
    v-bind="$attrs"
    @input="(...args) => emit('input', ...args)"
    @blur="onBlur"
  />
</template>
